package hotgammon.betamon;

import hotgammon.common.Color;
import hotgammon.common.Game;
import hotgammon.common.Location;
import hotgammon.common.ValidatorStrategy;

public class BetaValidatorStrategy  implements ValidatorStrategy{

	@Override
	public boolean isValid(Location from, Location to, int diceValue, Game game) {
		
		if (!isDirectionValid(from, to, game.getPlayerInTurn()))
			return false;

		int distanceToMove = Math.abs(Location.distance(from, to));


		if (game.getColor(to) != game.getPlayerInTurn() && game.getCount(to) > 1)
			return false;
		
		if (game.getCount(Location.R_BAR) != 0 && from != Location.R_BAR)
			return false;
		
		if (bearOffAttempt(to,game.getPlayerInTurn()))
		{
			if (distanceToMove > diceValue)
				return false;
			
			if (blackTriesToBearOffWithCheckersOutsideInnerTable(game)) {
				return false;
			}
			else if (redTriesToBearOffWithCheckersOutsideInnerTable(game))
				return false; 
			else if (redHasCheckersInInnerTableButWithOneOfDistanceLargerThanDiceValue(distanceToMove, diceValue, game))
				return false; 
			else if (blackHasCheckersInInnerTableButWithOneOfDistanceLargerThanDiceValue(distanceToMove, diceValue, game))
				return false; 
		}
		else if (distanceToMove != diceValue)
			return false;
		
		return true;
	}

	private boolean redHasCheckersInInnerTableButWithOneOfDistanceLargerThanDiceValue(int distance, int diceValue, Game game) {
		if (game.getPlayerInTurn() == Color.RED)
		{
			if (distance < diceValue) //Only allowed if no checkers has a larger distance to bear off
			{
				for(Location l : Location.values())
				{
					if (!Location.outsideBoard(l))
					{
						if (game.getCount(l) > 0 && game.getColor(l) == Color.RED) //Found a red checker on the board
						{
							if (Location.distance(l, Location.R_BEAR_OFF) > diceValue) //The found checker has a larger distance to bear off than allowed by the dice
								return true;
						}
					}
				}
			}
		}
		return false;
	}
	
	private boolean blackHasCheckersInInnerTableButWithOneOfDistanceLargerThanDiceValue(int distance, int diceValue, Game game) {
		if (game.getPlayerInTurn() == Color.BLACK)
		{
			if (distance < diceValue) //Only allowed if no checkers has a larger distance to bear off
			{
				for(Location l : Location.values())
				{
					if (!Location.outsideBoard(l))
					{
						if (game.getCount(l) > 0 && game.getColor(l) == Color.BLACK) //Found a black checker on the board
						{
							if (Location.distance(l, Location.B_BEAR_OFF) > diceValue) //The found checker has a larger distance to bear off than allowed by the dice
								return true;
						}
					}
				}
			}
		}
		return false;
	}

	private boolean blackTriesToBearOffWithCheckersOutsideInnerTable(Game game) {
		if (game.getPlayerInTurn() == Color.BLACK) {
			for (Location l : Location.values()) {
				if (!Location.partOfBlackInnerTable(l) && !Location.outsideBoard(l)) {
					if (game.getColor(l)==Color.BLACK)
						return true;
				}
			}
		}
		return false;
	}
	
	private boolean redTriesToBearOffWithCheckersOutsideInnerTable(Game game) {
		for (Location l : Location.values()) {
			if (!Location.partOfRedInnerTable(l) && !Location.outsideBoard(l)) {
				if (game.getColor(l)==Color.RED)
					return true;
			}
		}
		
		return false;
	}

	private boolean bearOffAttempt(Location to, Color playerInTurn) {
		boolean bearOffAttempt;
		if ( playerInTurn == Color.RED) {
			if (to == Location.B_BEAR_OFF)
				return false;
			bearOffAttempt = to == Location.R_BEAR_OFF;
		}
		else
		{
			if (to == Location.R_BEAR_OFF)
				return false;
			bearOffAttempt = to == Location.B_BEAR_OFF;
		}
		return bearOffAttempt;
	}

	private boolean isDirectionValid(Location from, Location to, Color playerInTurn) {
int signedDistance = Location.distance(from, to);
		
		if (signedDistance > 0 && playerInTurn == Color.RED) {
			return false;
		}
		if (signedDistance < 0 && playerInTurn == Color.BLACK)
			return false;
		
		return true;
	}

}
